{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Installing packages:\n",
      "\t.package(path: \"/home/saeta/fastai_docs/dev_swift/FastaiNotebook_10_mixup_ls\")\n",
      "\t\tFastaiNotebook_10_mixup_ls\n",
      "With SwiftPM flags: []\n",
      "Working in: /tmp/tmpi1s5nihp/swift-install\n",
      "[1/2] Compiling jupyterInstalledPackages jupyterInstalledPackages.swift\n",
      "[2/3] Merging module jupyterInstalledPackages\n",
      "Initializing Swift...\n",
      "Installation complete!\n"
     ]
    }
   ],
   "source": [
    "%install-location $cwd/swift-install\n",
    "%install '.package(path: \"$cwd/FastaiNotebook_10_mixup_ls\")' FastaiNotebook_10_mixup_ls"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import Foundation\n",
    "import TensorFlow\n",
    "import FastaiNotebook_10_mixup_ls\n",
    "import Path"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('inline', 'module://ipykernel.pylab.backend_inline')\n"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%include \"EnableIPythonDisplay.swift\"\n",
    "IPythonDisplay.shell.enable_matplotlib(\"inline\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Laying the groundwork"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Downloading the data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// hardcoded, should really generalise\n",
    "public func downloadSpeakers(path: Path = dataPath) -> Path {\n",
    "    let url = \"http://www.openslr.org/resources/45/ST-AEDS-20180100_1-OS.tgz\"\n",
    "    let fname = \"ST-AEDS-20180100_1-OS\"\n",
    "    let outDir = path/fname\n",
    "    let outFile = path/\"\\(fname).tgz\"\n",
    "    try! outDir.mkdir(.p)\n",
    "    if !outFile.exists {\n",
    "        downloadFile(url, dest:outFile.string)\n",
    "        _ = \"/bin/tar\".shell(\"-xzf\", outFile.string, \"-C\", outDir.string)\n",
    "    }\n",
    "    print(outDir, type(of: outDir))\n",
    "    return outDir\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/home/saeta/.fastai/data/ST-AEDS-20180100_1-OS Path\r\n"
     ]
    }
   ],
   "source": [
    "let path = downloadSpeakers()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Opening WAVs in TensorFlow"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Luckily, TensorFlow has a \"decodeWav\" function. Let's extend the StringTensor to provide swifty access to this function, the same way we did with JPGs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "public extension StringTensor {\n",
    "    // Decode a StringTensor holding a path to a WAV file into (audio: Tensor<Float>, sampleRate: Tensor<Int32>)\n",
    "    func decodeWav() -> (audio: Tensor<Float>, sampleRate: Tensor<Int32>) {\n",
    "        return Raw.decodeWav(contents: self)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Single example file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/home/saeta/.fastai/data/ST-AEDS-20180100_1-OS/m0002_us_m0002_00056.wav\r\n"
     ]
    }
   ],
   "source": [
    "let wav = path.ls()[0].path.string\n",
    "print(wav)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let (sig, sr) = StringTensor(readFile: wav).decodeWav()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### To Spectrogram"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Luckily, TensorFlow has a couple of basic signal ops, including to Spectrogram."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let spec = Raw.audioSpectrogram(sig, \n",
    "                                windowSize: 1024, stride: 256, magnitudeSquared: false)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Utility to look at a spectrogram. Note the axes don't line up with what you'd expect from a typical spectrogram - here the X axis is frequency and the Y axis is time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "func showSpec(s: Tensor<Float>) {\n",
    "    plt.imshow(s.makeNumpyArray()[0], cmap: \"plasma\")\n",
    "    plt.show()\n",
    "    print(\"Shape: \\(s.shape)\\nMin:\\(s.min()), max: \\(s.max()), mean: \\(s.mean()), var: \\(s.variance())\")\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Shape: [1, 209, 513]\r\n",
      "Min:1.2907397e-05, max: 16.511257, mean: 0.076232545, var: 0.15422489\r\n"
     ]
    }
   ],
   "source": [
    "showSpec(s: spec)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### To MFCCs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that MFCCs are different from melspectrograms. It seems TF doesn't have a melspectrogram transform built-in. MFCCs at least have been used before so it doesn't seem crazy to use them instead, although they are generally used to intentionally reduce the dimensionality of the data, so we might be throwing away info that the NN could use. On the other hand we might be making it easier for the NN to find features it would've had to spend time finding itself. We'll give it a shot. On the plus side, it means much \"smaller images\"."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[TF defaults](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/ops/audio_ops.cc#L147) for MFCCs:\n",
    "```\n",
    "    .Attr(\"upper_frequency_limit: float = 4000\")\n",
    "    .Attr(\"lower_frequency_limit: float = 20\")\n",
    "    .Attr(\"filterbank_channel_count: int = 40\")\n",
    "    .Attr(\"dct_coefficient_count: int = 13\")\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let mfccs = Raw.mfcc(spectrogram: spec, sampleRate: sr, \n",
    "                       upperFrequencyLimit: 8000, lowerFrequencyLimit: 20, \n",
    "                       filterbankChannelCount: 40, dctCoefficientCount: 13)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Shape: [1, 209, 13]\r\n",
      "Min:-8.186757, max: 13.762619, mean: -0.015072358, var: 4.264482\r\n"
     ]
    }
   ],
   "source": [
    "showSpec(s: mfccs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Using fastai - datablocks, labelers, splitters etc."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let il = ItemList(fromFolder: path, extensions: [\"wav\", \"WAV\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// export\n",
    "public func randomSplitter(fName: Path, val_pct: Float) -> Bool {\n",
    "    return Float.random(in: 0.0...1.0) < val_pct\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let sd = SplitData(il) { randomSplitter(fName: $0, val_pct: 0.2) }"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We need a RegexLabeler. In python this was\n",
    "```python\n",
    "def re_labeler(fn, pat): return re.findall(pat, str(fn))[0]\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "public func reLabeler(_ fName: Path, pat: String) -> String {\n",
    "    // Gotta slice the input using the found range, then cast that `Substring` to `String`\n",
    "    // Seems too clunky to be true but it does work\n",
    "    // Needs a guard if re doesn't match\n",
    "    return String(fName.string[fName.string.findFirst(pat: pat)!])\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let pat = \"[mf]\\\\d+\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let wavpath = sd.train.items[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "m0002\r\n"
     ]
    }
   ],
   "source": [
    "print(reLabeler(wavpath, pat: pat))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// Surely this isn't how I'm supposed to do a 'partial' in Swift??\n",
    "// Only doing it because I couldn't get SplitLabeledData to work with a 2-arg fromFunc\n",
    "func speakerLabeler (item: Path) -> String {\n",
    "    return reLabeler(item, pat: pat)\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "m0002\r\n"
     ]
    }
   ],
   "source": [
    "print(speakerLabeler(item: wavpath))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\"No-op\" and Category processors. According to `11_imagenette`, we need these; I don't grok why yet."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "var (procItem,procLabel) = (NoopProcessor<Path>(),CategoryProcessor())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let sld = SplitLabeledData(sd, fromFunc: speakerLabeler, procItem: &procItem, procLabel: &procLabel)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Path : /home/saeta/.fastai/data/ST-AEDS-20180100_1-OS/m0002_us_m0002_00056.wav\r\n",
      "Int32 : 6\r\n",
      "String : m0002\r\n",
      "Array<String> : [\"f0001\", \"f0002\", \"f0003\", \"f0004\", \"f0005\", \"m0001\", \"m0002\", \"m0003\", \"m0004\", \"m0005\"]\r\n"
     ]
    }
   ],
   "source": [
    "// What did that do?\n",
    "print(type(of: sld.train.items[0]),\":\", sld.train.items[0])\n",
    "print(type(of: sld.train.labels[0]),\":\", sld.train.labels[0])\n",
    "print(type(of: sld.train.rawLabel(0)),\":\", sld.train.rawLabel(0))\n",
    "print(type(of: sld.train.procLabel.vocab!),\":\", sld.train.procLabel.vocab!)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let rawData = sld.toDataBunch(itemToTensor: pathsToTensor, labelToTensor: intsToTensor, bs: 64)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Optional(FastaiNotebook_10_mixup_ls.LabeledElement<TensorFlow.StringTensor, TensorFlow.Tensor<Swift.Int32>>(xb: TensorFlow.StringTensor(handle: TensorFlow.TensorHandle<Swift.String>(handle: TensorFlow.TFETensorHandle)), yb: [1, 7, 1, 8, 8, 0, 0, 2, 5, 0, 0, 3, 3, 5, 9, 7, 0, 1, 6, 6, 2, 7, 3, 7, 2, 1, 0, 3, 9, 6, 1, 9, 2, 9, 2, 1, 3, 3, 5, 5, 2, 6, 2, 2, 7, 6, 2, 3, 9, 4, 7, 3, 1, 4, 5, 4, 7, 6, 6, 5, 7, 0, 1, 2]))\r\n"
     ]
    }
   ],
   "source": [
    "print(rawData.train.oneBatch())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that the `xb` of `rawData` is full of `StringTensor`s, not `FloatTensors` - that's because we've got to load them into first WAVs, then spectrograms.\n",
    "\n",
    "I'm going to load and spectrogrammify them in the same transform because I don't know how to appy >1 transform at a time yet."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Also, if we put it in a Databunch now it wouldn't work because the WAVs are different lengths. We could make this easier on ourselves by pre-processing in a different notebook/step, but let's trim the tensors to a given length after we load them.\n",
    "\n",
    "I'm not clear on whether this ought to be done as a Processor or a Transform. Here, I'll do it in a Transform, because I'm confused by the Processor - particularly the `deprocess` methods (and also because I don't know how to apply >1 tfm)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "public func openAndTrimAndSpectro(fname: StringTensor, len: Int = 16000, \n",
    "                                 windowSize: Int64 = 1024, stride: Int64 = 256, \n",
    "                                 magnitudeSquared: Bool = false) -> TF{\n",
    "    let (sig,sr) = StringTensor(readFile: fname).decodeWav()\n",
    "    let shortSig = sig[..<len]\n",
    "    let spec = Raw.audioSpectrogram(shortSig, \n",
    "                                windowSize: windowSize, stride: stride, \n",
    "                                    magnitudeSquared: magnitudeSquared)\n",
    "    return spec\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let data = transformData(rawData, tfmItem: { openAndTrimAndSpectro(fname: $0, \n",
    "                                                                  len: 16000,\n",
    "                                                                  windowSize:1024,\n",
    "                                                                  stride:128,\n",
    "                                                                  magnitudeSquared:false) })"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let batch = data.train.oneBatch()!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// clone of 08_data_block.showImages, except the dimension to imshow()\n",
    "public func showSpecs(_ xb: TF, labels: [String]? = nil) {\n",
    "    let (rows,cols) = (3,3)\n",
    "//     plt.figure(figsize: [9, 9])\n",
    "    for i in 0..<(rows * cols) {\n",
    "        let img = plt.subplot(rows, cols, i + 1)\n",
    "        img.axis(\"off\")\n",
    "        let x = xb[i].makeNumpyArray()\n",
    "        img.imshow(x[0]) // <- this is why it's different to showImg, dims are different\n",
    "        if labels != nil { img.set_title(labels![i]) }\n",
    "        if (i + 1) >= (rows * cols) { break }\n",
    "    }\n",
    "    plt.tight_layout()\n",
    "    plt.show()\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 9 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "let labels = batch.yb.scalars.map { sld.train.procLabel.vocab![Int($0)] }\n",
    "showSpecs(batch.xb, labels: labels)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Training"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 08_data_block method — **CRASHES THE KERNEL.**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Stolen wholesale & without thinking from `08_data_block`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "error: <Cell 33>:2:23: error: use of undeclared type 'CNNModel'\nfunc optFunc(_ model: CNNModel) -> SGD<CNNModel> { return SGD(for: model, learningRate: 0.1) }\n                      ^~~~~~~~\n\nerror: <Cell 33>:2:40: error: use of undeclared type 'CNNModel'\nfunc optFunc(_ model: CNNModel) -> SGD<CNNModel> { return SGD(for: model, learningRate: 0.1) }\n                                       ^~~~~~~~\n\nerror: <Cell 33>:3:21: error: use of undeclared type 'CNNModel'\nfunc modelInit() -> CNNModel { return CNNModel(channelIn: 1, nOut: 10, filters: [64, 64, 128, 256]) }\n                    ^~~~~~~~\n\n"
     ]
    }
   ],
   "source": [
    "// Using CNNModel as defined in 08_data_block notebook.\n",
    "func optFunc(_ model: CNNModel) -> SGD<CNNModel> { return SGD(for: model, learningRate: 0.1) }\n",
    "func modelInit() -> CNNModel { return CNNModel(channelIn: 1, nOut: 10, filters: [64, 64, 128, 256]) }\n",
    "let learner = Learner(data: data, lossFunc: softmaxCrossEntropy, optFunc: optFunc, modelInit: modelInit)\n",
    "let recorder = learner.makeDefaultDelegates(metrics: [accuracy])\n",
    "// learner.addDelegate(learner.makeNormalize(mean: imagenetStats.mean, std: imagenetStats.std))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's try to get our dataset stats for normalization, in case that makes a difference. I don't think it will, because `08_data_block` runs fine both with & without the normalizer."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// learner.fit(1) // CRASHES KERNEL; TF-619"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 11_imagenette method  — **CRASHES THE KERNEL.**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Stolen wholesale & without thinking from `11_imagenette`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "public struct ConvLayer: Layer {\n",
    "    public var bn: FABatchNorm<Float>\n",
    "    public var conv: FANoBiasConv2D<Float>\n",
    "    \n",
    "    public init(_ cIn: Int, _ cOut: Int, ks: Int = 3, stride: Int = 1, zeroBn: Bool = false, act: Bool = true){\n",
    "        bn = FABatchNorm(featureCount: cOut)\n",
    "        conv = FANoBiasConv2D(cIn, cOut, ks: ks, stride: stride, activation: act ? relu : identity)\n",
    "        if zeroBn { bn.scale = Tensor(zeros: [cOut]) }\n",
    "    }\n",
    "    \n",
    "    @differentiable\n",
    "    public func callAsFunction(_ input: TF) -> TF {\n",
    "        return bn(conv(input))\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "//A layer that you can switch off to do the identity instead\n",
    "public protocol SwitchableLayer: Layer {\n",
    "    associatedtype Input\n",
    "    var isOn: Bool {get set}\n",
    "    \n",
    "    @differentiable func forward(_ input: Input) -> Input\n",
    "}\n",
    "\n",
    "public extension SwitchableLayer {\n",
    "    func callAsFunction(_ input: Input) -> Input {\n",
    "        return isOn ? forward(input) : input\n",
    "    }\n",
    "\n",
    "    @differentiating(callAsFunction)\n",
    "    func gradForward(_ input: Input) ->\n",
    "        (value: Input, pullback: (Self.Input.TangentVector) ->\n",
    "            (Self.TangentVector, Self.Input.TangentVector)) {\n",
    "        if isOn { return valueWithPullback(at: input) { $0($1) } }\n",
    "        else { return (input, {v in return (Self.TangentVector.zero, v)}) }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "public struct MaybeAvgPool2D: SwitchableLayer {\n",
    "    var pool: FAAvgPool2D<Float>\n",
    "    @noDerivative public var isOn = false\n",
    "    \n",
    "    @differentiable public func forward(_ input: TF) -> TF { return pool(input) }\n",
    "    \n",
    "    public init(_ sz: Int) {\n",
    "        isOn = (sz > 1)\n",
    "        pool = FAAvgPool2D<Float>(sz)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "public struct MaybeConv: SwitchableLayer {\n",
    "    var conv: ConvLayer\n",
    "    @noDerivative public var isOn = false\n",
    "    \n",
    "    @differentiable public func forward(_ input: TF) -> TF { return conv(input) }\n",
    "    \n",
    "    public init(_ cIn: Int, _ cOut: Int) {\n",
    "        isOn = (cIn > 1) || (cOut > 1)\n",
    "        conv = ConvLayer(cIn, cOut, ks: 1, act: false)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "public struct ResBlock: Layer {\n",
    "    public var convs: [ConvLayer]\n",
    "    public var idConv: MaybeConv\n",
    "    public var pool: MaybeAvgPool2D\n",
    "    \n",
    "    public init(_ expansion: Int, _ ni: Int, _ nh: Int, stride: Int = 1){\n",
    "        let (nf, nin) = (nh*expansion,ni*expansion)\n",
    "        convs = [ConvLayer(nin, nh, ks: 1)]\n",
    "        convs += (expansion==1) ? [\n",
    "            ConvLayer(nh, nf, ks: 3, stride: stride, zeroBn: true, act: false)\n",
    "        ] : [\n",
    "            ConvLayer(nh, nh, ks: 3, stride: stride),\n",
    "            ConvLayer(nh, nf, ks: 1, zeroBn: true, act: false)\n",
    "        ]\n",
    "        idConv = nin==nf ? MaybeConv(1,1) : MaybeConv(nin, nf)\n",
    "        pool = MaybeAvgPool2D(stride)\n",
    "    }\n",
    "    \n",
    "    @differentiable\n",
    "    public func callAsFunction(_ inp: TF) -> TF {\n",
    "        return relu(convs(inp) + idConv(pool(inp)))\n",
    "    }\n",
    "    \n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "func makeLayer(_ expansion: Int, _ ni: Int, _ nf: Int, _ nBlocks: Int, stride: Int) -> [ResBlock] {\n",
    "    return Array(0..<nBlocks).map { ResBlock(expansion, $0==0 ? ni : nf, nf, stride: $0==0 ? stride : 1) }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "public struct XResNet: Layer {\n",
    "    public var stem: [ConvLayer]\n",
    "    public var maxPool = MaxPool2D<Float>(poolSize: (3,3), strides: (2,2), padding: .same)\n",
    "    public var blocks: [ResBlock]\n",
    "    public var pool = GlobalAvgPool2D<Float>()\n",
    "    public var linear: Dense<Float>\n",
    "    \n",
    "    public init(_ expansion: Int, _ layers: [Int], cIn: Int = 3, cOut: Int = 1000){\n",
    "        var nfs = [cIn, (cIn+1)*8, 64, 64]\n",
    "        stem = Array(0..<3).map{ ConvLayer(nfs[$0], nfs[$0+1], stride: $0==0 ? 2 : 1)}\n",
    "        nfs = [64/expansion,64,128,256,512]\n",
    "        blocks = Array(layers.enumerated()).map { (i,l) in \n",
    "            return makeLayer(expansion, nfs[i], nfs[i+1], l, stride: i==0 ? 1 : 2)\n",
    "        }.reduce([], +)\n",
    "        linear = Dense(inputSize: nfs.last!*expansion, outputSize: cOut)\n",
    "    }\n",
    "    \n",
    "    @differentiable\n",
    "    public func callAsFunction(_ inp: TF) -> TF {\n",
    "        return linear(pool(blocks(maxPool(stem(inp)))))\n",
    "    }\n",
    "    \n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "func xresnet18 (cIn: Int = 3, cOut: Int = 1000) -> XResNet { return XResNet(1, [2, 2, 2, 2], cIn: cIn, cOut: cOut) }\n",
    "func xresnet34 (cIn: Int = 3, cOut: Int = 1000) -> XResNet { return XResNet(1, [3, 4, 6, 3], cIn: cIn, cOut: cOut) }\n",
    "func xresnet50 (cIn: Int = 3, cOut: Int = 1000) -> XResNet { return XResNet(4, [3, 4, 6, 3], cIn: cIn, cOut: cOut) }\n",
    "func xresnet101(cIn: Int = 3, cOut: Int = 1000) -> XResNet { return XResNet(4, [3, 4, 23, 3], cIn: cIn, cOut: cOut) }\n",
    "func xresnet152(cIn: Int = 3, cOut: Int = 1000) -> XResNet { return XResNet(4, [3, 8, 36, 3], cIn: cIn, cOut: cOut) }"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "func modelInit() -> XResNet { return xresnet34(cIn: 1, cOut: 10) }"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let optFunc: (XResNet) -> StatefulOptimizer<XResNet> = adamOpt(lr: 1e-3, mom: 0.9, beta: 0.99, wd: 1e-2, eps: 1e-6)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let learner = Learner(data: data, lossFunc: softmaxCrossEntropy, optFunc: optFunc, modelInit: modelInit)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let recorder = learner.makeDefaultDelegates(metrics: [accuracy])\n",
    "// learner.addDelegate(learner.makeNormalize(mean: imagenetStats.mean, std: imagenetStats.std))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "learner.addOneCycleDelegates(1e-3, pctStart: 0.5)\n",
    "// learner.fit(5) // CRASHES KERNEL; TF-619"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Fin."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Swift",
   "language": "swift",
   "name": "swift"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
